﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace RocketRiotDestructibleTexture
{

    public class RiotTexture
    {
        public Texture2D Texture
        {
            get { return _texture; }
            set
            {
                _texture = value;
            }
        }
        private Texture2D _texture;


        private const int MaxVertices = 160000;
        private const int MaxIndices = 160000;

        public Effect Effect { get; set; }
        public readonly float Depth;
        public readonly Vector2 QuadSize;

        public int NumVertices { get; private set; }
        public int NumIndices { get; private set; }

        public int PrimitiveCount { get; private set; }

        public int StartIndex { get; private set; }
        public int VertexOffset { get; private set; }

        private readonly short[] _indices;
        private readonly VertexPositionColor[] _vertices;

        private GraphicsDevice _graphicsDevice;

        // Calculate the quad corners
        private readonly Vector3 _left;
        private readonly Vector3 _upperLeft;
        private readonly Vector3 _upperRight;
        private readonly Vector3 _lowerLeft;
        private readonly Vector3 _lowerRight;


        public VertexPositionColor[] Vertices { get { return _vertices; } }
        public short[] Indices { get { return _indices; } }

        public RiotTexture(GraphicsDevice graphicsDevice, Texture2D texture, float depth, Vector2 quadSize, Vector3 normal, Vector3 up)
        {
            Texture = texture;
            QuadSize = quadSize;
            Depth = depth;

            _graphicsDevice = graphicsDevice;

            _indices = new short[MaxIndices];
            _vertices = new VertexPositionColor[MaxVertices];

            // Calculate the quad corners
            _left = Vector3.Cross(normal, up);
            Vector3 uppercenter = (up * QuadSize.Y / 2);
            _upperLeft = uppercenter + (_left * QuadSize.X / 2);
            _upperRight = uppercenter - (_left * QuadSize.X / 2);
            _lowerLeft = _upperLeft - (up * QuadSize.Y);
            _lowerRight = _upperRight - (up * QuadSize.Y);

            StartIndex = 0;
            VertexOffset = 0;

            BasicEffect effect = new BasicEffect(_graphicsDevice) {TextureEnabled = false, VertexColorEnabled = true};
            Effect = effect;

            UpdateVertex(texture);
            UpdateIndices(texture);
        }

        public void UpdateVertex(Texture2D texture)
        {
            NumVertices = 0;

            Color[] pixels = new Color[texture.Width * texture.Height];
            texture.GetData(pixels);

            int textureWidth = texture.Width;

            //Vector3 textureCenter = new Vector3(texture.Width / 2f * -1 * QuadSize.X, texture.Height / 2f * QuadSize.Y, 0f);
            Vector3 textureCenter = new Vector3((texture.Width / 2f) * QuadSize.X, (texture.Height / 2f) * QuadSize.Y, 0f);

            for (int i = 0; i < pixels.Length; i++)
            {
                int x = i % textureWidth;
                int y = i / textureWidth;

                //space relating to the column/line of the texture
                Vector3 spacing = new Vector3(x * QuadSize.X, y * QuadSize.Y * -1, 0f);

                Color pixel = pixels[i];

                Vector3 offset = spacing - (textureCenter * new Vector3(1f, -1f, 0f));

                #region TopVertex

                //LowerLeft - 0
                _vertices[NumVertices].Position = _lowerLeft + offset;
                _vertices[NumVertices].Color = pixel;

                //UpperLeft - 1
                _vertices[NumVertices + 1].Position = _upperLeft + offset;
                _vertices[NumVertices + 1].Color = pixel;

                //LowerRight - 2
                _vertices[NumVertices + 2].Position = _lowerRight + offset;
                _vertices[NumVertices + 2].Color = pixel;

                //UpperRight - 3
                _vertices[NumVertices + 3].Position = _upperRight + offset;
                _vertices[NumVertices + 3].Color = pixel;

                #endregion

                #region BottomVertex

                //LowerLeft - 4
                _vertices[NumVertices + 4].Position = _lowerLeft + offset - new Vector3(0, 0, Depth);
                _vertices[NumVertices + 4].Color = pixel * 0f;

                //UpperLeft - 5
                _vertices[NumVertices + 5].Position = _upperLeft + offset - new Vector3(0, 0, Depth);
                _vertices[NumVertices + 5].Color = pixel * 0f;

                //LowerRight - 6
                _vertices[NumVertices + 6].Position = _lowerRight + offset - new Vector3(0, 0, Depth);
                _vertices[NumVertices + 6].Color = pixel * 0f;

                //UpperRight - 7
                _vertices[NumVertices + 7].Position = _upperRight + offset - new Vector3(0, 0, Depth);
                _vertices[NumVertices + 7].Color = pixel * 0f;

                #endregion

                NumVertices += 8;
            }
        }

        public void UpdateIndices(Texture2D texture)
        {
            NumIndices = 0;
            PrimitiveCount = 0;

            Color[] pixels = new Color[texture.Width*texture.Height];
            texture.GetData(pixels);

            int textureWidth = texture.Width;

            for (int i = 0; i < pixels.Length; i++)
            {
                int numVertex = i*8;

                int x = i%textureWidth;
                int y = i/textureWidth;

                Color pixel = pixels[i];

                if (pixel.A > 0)
                {
                    SetIndex((short)numVertex, (short)(numVertex + 1), (short)(numVertex + 2),
                             (short)(numVertex + 3));

                    //LookUp
                    if (y == 0 || pixels[x + (y - 1)*texture.Width].A == 0)
                    {
                        SetIndex((short)(numVertex + 5), (short)(numVertex + 7), (short)(numVertex + 1),
                                     (short)(numVertex + 3));
                    }

                    //LookDown
                    if (y == texture.Height - 1 || pixels[x + (y + 1) * texture.Width].A == 0)
                    {
                        SetIndex((short)(numVertex + 0), (short)(numVertex + 2), (short)(numVertex + 4),
                                     (short)(numVertex + 6));
                    }

                    //LookLeft
                    if (x == 0 || pixels[(x - 1) + y * texture.Width].A == 0)
                    {
                        SetIndex((short)(numVertex + 4), (short)(numVertex + 5), (short)(numVertex + 0),
                                 (short)(numVertex + 1));
                    }

                    //LookRight
                    if (x == texture.Width - 1 || pixels[(x + 1) + y * texture.Width].A == 0)
                    {
                        SetIndex((short)(numVertex + 2), (short)(numVertex + 3), (short)(numVertex + 6),
                                 (short)(numVertex + 7));
                    }
                }
            }
        }

        private void SetIndex(short lowerLeft, short upperLeft, short lowerRight, short upperRight)
        {
            _indices[NumIndices++] = lowerLeft;
            _indices[NumIndices++] = upperLeft;
            _indices[NumIndices++] = lowerRight;

            _indices[NumIndices++] = lowerRight;
            _indices[NumIndices++] = upperLeft;
            _indices[NumIndices++] = upperRight;

            PrimitiveCount += 2;
        }
    }
}
